package com.personal.datacompare.tree;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.personal.core.bean.CountEntity;
import com.personal.core.data.DataColumn;
import com.personal.core.data.DataRow;
import com.personal.core.data.DataTable;
import com.personal.core.utils.Assert;
import com.personal.core.utils.CoreUtil;
import com.personal.core.utils.DeepChildrenUtil;
import com.personal.core.utils.ReGularUtil;
import com.personal.core.utils.SimilarityUtil;
import com.personal.datacompare.api.CompareDataTable;
import com.personal.datacompare.config.CheckColumnConfig;
import com.personal.datacompare.config.ColumnConfig;
import com.personal.datacompare.config.CombineColumnConfig;
import com.personal.datacompare.config.CompareColumnConfig;
import com.personal.datacompare.config.CompareDataTableConfig;
import com.personal.datacompare.config.CompareDataTableConfig.ColumnLoopTypeEnum;
import com.personal.datacompare.config.CoverColumnConfig;
import com.personal.datacompare.config.DisplayColumnConfig;
import com.personal.datacompare.config.ExtendColumnConfig;
import com.personal.dataconvert.DataTable2Html;
import com.personal.dataconvert.bean.HeaderConfig;
import com.personal.dataconvert.port.Data2Html;
import com.personal.dataconvert.util.ExcelHtmlUtil;

/**
 * 抽象的树对比 复杂抽象树的对比，只支持显示列，对比列（三棵树以上不支持差值，差率），合并列，对比显示列，覆盖列
 * @author cuibo
 */
public abstract class AbstractCompareTree extends ITree<DataTable, DataRow>
{
    /**
     * 
     */
    private static final long serialVersionUID = 8492552423131818615L;

    /** 配置信息 */
    protected CompareDataTableConfig tableConfig;

    /** 合并的树集合 */
    protected List<AbstractCompareTree> combineTrees;

    @Override
    public List<CompareTreeNode> recursionGetTreeNodes()
    {
        List<? extends ITreeNode<DataTable, DataRow>> tempResult = super.recursionGetTreeNodes();
        if (tempResult == null || tempResult.isEmpty())
        {
            return null;
        }
        List<CompareTreeNode> result = new ArrayList<CompareTreeNode>();
        for (ITreeNode<DataTable, DataRow> tempNode : tempResult)
        {
            if (!(tempNode instanceof CompareTreeNode))
            {
                continue;
            }
            result.add((CompareTreeNode) tempNode);
        }
        return result;
    }

    public AbstractCompareTree()
    {
    }

    public AbstractCompareTree(CompareDataTableConfig tableConfig)
    {
        this(null, tableConfig);
    }

    /**
     * @param source 数据源
     * @param tableConfig 配置信息
     * @throws Exception
     */
    public AbstractCompareTree(DataTable source, CompareDataTableConfig tableConfig)
    {
        super(source);
        this.tableConfig = tableConfig;
        Assert.isNotNull(tableConfig, "报表配置信息为空！");
    }

    /**
     * 抽象方法
     * @param row
     * @param isFirst
     * @param isLast
     * @return  -1 上一个节点的子节点  -2 上一个节点的兄弟节点
     * @throws Exception
     */
    public abstract int getDataRowDeepLength(DataRow row, boolean isFirst, boolean isLast) throws Exception;

    /**
     * 构建树
     * @throws Exception
     */
    @Override
    public AbstractCompareTree build() throws Exception
    {
        convertRow2TreeNode();
        return this;
    }

    /**
     * 把DataRow转成TreeNode节点 cb 2017 04 09 将该方法设置为保护的，如子类可以需要特殊处理，供子类覆盖
     * @throws Exception
     */
    protected void convertRow2TreeNode() throws Exception
    {
        if (source.getRows() == null || source.getRows().isEmpty())
        {
            return;
        }
        // 序号
        int index = -1;
        // 实际的序号
        int relIndex = -1;
        // 当前的父亲节点
        ITreeNode<DataTable, DataRow> tempNode = null;
        // 当前遍历行的深度
        int currentDeep = -2;
        
        boolean isNullRow = false;
        for (DataRow row : source.getRows())
        {
            index++;
            if (row == null || row.getItemMap() == null)
            {
                continue;
            }
            // 过滤空行
            isNullRow = true;
            for (Entry<String, Object> entry : row.getItemMap().entrySet())
            {
                if (!CoreUtil.isEmpty(entry.getValue()))
                {
                    isNullRow = false;
                    break;
                }
            }
            if (isNullRow)
            {
                continue;
            }
            relIndex++;
            // 获取当前DataRow的深度
            currentDeep = getDataRowDeepLength(row, relIndex == 0, index == source.getRows().size() - 1);
            // 将当前节点添加到树中
            tempNode = addNode2Tree(row, currentDeep, tempNode);
        }
    }

    /**
     * 将node添加到树中
     * @param row
     * @param currentDeep  -1 上一个节点的子节点  -2 上一个节点的兄弟节点
     * @param tempNode
     * @return
     */
    protected ITreeNode<DataTable, DataRow> addNode2Tree(DataRow row, int currentDeep, ITreeNode<DataTable, DataRow> tempNode)
    {
        ITreeNode<DataTable, DataRow> newNode = new CompareTreeNode(row, tableConfig, this);
        newNode.setDeepLength(currentDeep);
        if (tempNode == null)
        {
            // 第一层
            this.getChilds().add(newNode);
        }
        else
        {
            switch (currentDeep)
            {
            case -1:
                // 作为当前tempNode的子节点
                tempNode.getChildren().add(newNode);
                newNode.setParent(tempNode);
                newNode.setDeepLength(tempNode.getDeepLength() + 1);
                break;
            case -2:
                // 作为当前tempNode的兄弟节点
                newNode.setDeepLength(tempNode.getDeepLength());
                ITreeNode<DataTable, DataRow> localParent = tempNode.getParent();
                if (localParent != null)
                {
                    localParent.getChildren().add(newNode);
                    newNode.setParent(localParent);
                } else 
                {
                    tempNode.getRoot().getChilds().add(newNode);
                }
                break;
            default:
                // 如果currentDeep小于tempNode的深度，则查找tempNode的父亲节点，并且一直找到是currentDeep的深度减一的那个节点，把newNode作为那个节点的子节点，
                if (currentDeep < tempNode.getDeepLength())
                {
                    ITreeNode<DataTable, DataRow> parent = tempNode;
                    while (currentDeep <= parent.getDeepLength())
                    {
                        parent = parent.getParent();
                        if (parent == null)
                        {
                            break;
                        }
                    }
                    if (parent == null)
                    {
                        // 无法处理的数据当做第一层(但是第一层的深度不一定是1)
                        if (tempNode.getRoot().getChilds().size() > 0)
                        {
                            newNode.setDeepLength(tempNode.getRoot().getChilds().get(0).getDeepLength());
                        } else 
                        {
                            newNode.setDeepLength(1);
                        }
                        tempNode.getRoot().getChilds().add(newNode);
                    }
                    else
                    {
                        newNode.setParent(parent);
                        parent.getChildren().add(newNode);
                    }
                }
                else if (currentDeep == tempNode.getDeepLength())
                {
                    // 是当前temp节点的兄弟节点
                    if (tempNode.getParent() == null)
                    {
                        tempNode.getRoot().getChilds().add(newNode);
                    }
                    else
                    {
                        newNode.setParent(tempNode.getParent());
                        tempNode.getParent().getChildren().add(newNode);
                    }
                }
                else if (currentDeep > tempNode.getDeepLength())
                {
                    // 是当前temp的子节点
                    newNode.setParent(tempNode);
                    tempNode.getChildren().add(newNode);
                }
                break;
            }
        }
        return newNode;
    }

    @Override
    public AbstractCompareTree combine(ITree<DataTable, DataRow> otherTree) throws Exception
    {
        Assert.isNotNull(tableConfig.getEqualsColumnConfig(), "判断相等列配置信息为空！");
        // 没有数据或者数据不合法直接返回。
        if (otherTree != null && this.getClass() != otherTree.getClass())
        {
            throw new Exception("不同类型的Tree不允许合并！");
        }

        AbstractCompareTree otherTemp = (AbstractCompareTree) otherTree;
        // 添加合并树到其对应的合并树列表中
        getCombineTrees().add(otherTemp);
        // 如果两棵树均为空，则直接返回
        if (this.getChilds() == null || this.getChilds().isEmpty())
        {
            if (otherTree == null || otherTree.getChilds() == null || otherTree.getChilds().isEmpty())
            {
                return this;
            }
            else
            {
                // 拷贝第二棵树的第一个节点到第一颗树，全部设置为插入节点
                copyOtherTree2This(otherTree);
                return this;
            }
        }
        else
        {
            if (otherTree == null || otherTree.getChilds() == null || otherTree.getChilds().isEmpty())
            {
                return this;
            }
        }
        combineTreeNode(null, this.getChilds(), otherTemp, otherTemp.getChilds());
        return this;
    }

    /**
     * 将otherTree的所有节点插入到当前树中，并设置为插入节点
     * @param otherTree
     */
    private void copyOtherTree2This(ITree<DataTable, DataRow> otherTree)
    {
        for (ITreeNode<DataTable, DataRow> iTreeNode : otherTree.getChilds())
        {
            CompareTreeNode treeNode = (CompareTreeNode) iTreeNode;
            treeNode.setInsertNode(true, true);
        }
        this.getChilds().addAll(otherTree.getChilds());
    }

    /**
     * 获取能和当前树中所有节点能够匹配上的节点
     * @param otherTree
     * @return key 当前节点的树， vlaue：匹配树的节点
     * @throws Exception
     */
    @Override
    public Map<CompareTreeNode, CompareTreeNode> getMatchTreeNodes(ITree<DataTable, DataRow> otherTree) throws Exception
    {
        // 没有数据或者数据不合法直接返回。
        if (!(otherTree instanceof AbstractCompareTree))
        {
            throw new Exception("不同类型的Tree不允许合并！");
        }
        if (this.getChilds() == null || this.getChilds().isEmpty())
        {
            return null;
        }
        if (otherTree == null || otherTree.getChilds() == null || otherTree.getChilds().isEmpty())
        {
            return null;
        }
        Map<CompareTreeNode, CompareTreeNode> result = new LinkedHashMap<CompareTreeNode, CompareTreeNode>();
        loadMatchTreeNode(this.getChilds(), otherTree.getChilds(), result);
        return result;
    }

    /**
     * 加载匹配上的节点
     * @param source
     * @param target
     * @param result
     */
    private void loadMatchTreeNode(List<ITreeNode<DataTable, DataRow>> source, List<ITreeNode<DataTable, DataRow>> target, Map<CompareTreeNode, CompareTreeNode> result)
    {
        CompareTreeNode treeNode = null;
        CompareTreeNode matchNode = null;

        for (ITreeNode<DataTable, DataRow> iTreeNode : source)
        {
            if (!(iTreeNode instanceof CompareTreeNode))
            {
                continue;
            }
            treeNode = (CompareTreeNode) iTreeNode;

            // 去target中查找相等的节点，把那个节点上面的节点插入上面，并移除这些节点
            matchNode = lookForTreeNodeAndRemove(treeNode, target);
            if (matchNode == null)
            {
                continue;
            }
            result.put(treeNode, matchNode);
            if (!iTreeNode.getChildren().isEmpty() && !matchNode.getChildren().isEmpty())
            {
                loadMatchTreeNode(iTreeNode.getChildren(), matchNode.getChildren(), result);
            }
        }
    }

    @Override
    public AbstractCompareTree combine(List<ITree<DataTable, DataRow>> combineTrees) throws Exception
    {
        if (combineTrees == null || combineTrees.isEmpty())
        {
            return this;
        }
        AbstractCompareTree result = this;
        // 合并所有的树
        for (ITree<DataTable, DataRow> iTree : combineTrees)
        {
            result = result.combine(iTree);
        }
        return result;
    }
    
    /**
     * 合并树节点
     * @param parent
     * @param source
     * @param targeTree
     * @param target
     */
    protected void combineTreeNode(ITreeNode<DataTable, DataRow> parent, List<ITreeNode<DataTable, DataRow>> source, ITree<DataTable, DataRow> targeTree, List<ITreeNode<DataTable, DataRow>> target)
    {
        // 合并之后的结果
        List<ITreeNode<DataTable, DataRow>> result = new ArrayList<ITreeNode<DataTable, DataRow>>();

        CompareTreeNode treeNode = null;
        List<CompareTreeNode> lookForNodes = null;
        CompareTreeNode matchNode = null;

        // 所有没有匹配上的节点
        List<ITreeNode<DataTable, DataRow>> allNoMatchNodes = new ArrayList<ITreeNode<DataTable, DataRow>>();
        for (ITreeNode<DataTable, DataRow> iTreeNode : source)
        {
            if (!(iTreeNode instanceof CompareTreeNode))
            {
                continue;
            }
            treeNode = (CompareTreeNode) iTreeNode;
            // 默认在本次均没有匹配上和不是本次插入的节点
            treeNode.setThisHasMatch(false);
            treeNode.setThisInsertNode(false);

            // 去target中查找相等的节点，把那个节点上面的节点插入上面，并移除这些节点
            lookForNodes = lookForTreeNodesByCofing(treeNode, target);
            if (lookForNodes == null || lookForNodes.isEmpty())
            {
                result.add(treeNode);
                continue;
            }
            // 把target中的数据移除，这样可以减少下次循环个数
            int removeIndex = 0;
            for (Iterator<ITreeNode<DataTable, DataRow>> iterator = target.iterator(); iterator.hasNext();)
            {
                ITreeNode<DataTable, DataRow> next = iterator.next();
                if (removeIndex++ >= lookForNodes.size())
                {
                    break;
                }
                // 添加没有匹配上的另一颗树的节点到所有的未匹配节点中
                if (removeIndex < lookForNodes.size())
                {
                    allNoMatchNodes.add(next);
                }
                iterator.remove();
            }
            // 上一步是百分百添加了插入节点，此时就需要处理
            if (!tableConfig.isInsertNoMatch())
            {
                // 只取最后一个节点
                lookForNodes = lookForNodes.subList(lookForNodes.size() - 1, lookForNodes.size());
            }
            // 递归匹配合并子节点：此时的matchNode是当前节点
            matchNode = (CompareTreeNode) lookForNodes.get(lookForNodes.size() - 1);
            // 获取matchNode匹配上的那个节点
            matchNode = matchNode.getMatchNodes().get(targeTree.getSource());
            // cb 2017 12 04此时应该对 lookForNodes和result上面的没有匹配的节点做大小的判断。
            addFindNodesToResult(result, lookForNodes);
            
            //result.addAll(lookForNodes);
            if (!iTreeNode.getChildren().isEmpty() && !matchNode.getChildren().isEmpty())
            {
                // 此时的matchNode是当前节点
                combineTreeNode(iTreeNode, iTreeNode.getChildren(), targeTree, matchNode.getChildren());
            }
            else if (!matchNode.getChildren().isEmpty() && tableConfig.isInsertNoMatch())
            {
                // 如果当前节点没有子节点了，但是匹配的节点还有子节点，仍需要加入,但都是插入节点
                for (ITreeNode<DataTable, DataRow> node : matchNode.getChildren())
                {
                    if (!(node instanceof CompareTreeNode))
                    {
                        continue;
                    }
                    CompareTreeNode compareTreeNode = (CompareTreeNode) node;
                    compareTreeNode.setInsertNode(true, true);
                    iTreeNode.getChildren().add(node);
                }
            }
        }
        // 2017/06/16 新增回溯判定 此时仍然需要再次查找一遍，防止出现 1,2 和 2,1 这样的漏网之鱼
        if (tableConfig.isRecall() && !allNoMatchNodes.isEmpty())
        {
            reCallMatchTreeNodes(result, allNoMatchNodes);
        }
        // 如果target中仍然还有数据，则插入进去，设置为是插入的节点
        if (!target.isEmpty() && tableConfig.isInsertNoMatch())
        {
            for (ITreeNode<DataTable, DataRow> iTreeNode : target)
            {
                if (!(iTreeNode instanceof CompareTreeNode))
                {
                    continue;
                }
                treeNode = (CompareTreeNode) iTreeNode;
                treeNode.setInsertNode(true, true);
            }
            // 此处插入时仍然要排序
            addFindNodesToResult(result, target);
        }
        // 不是第一层
        if (parent != null)
        {
            parent.setChildren(result);
        }
        else
        {
            // 第一层
            this.setChilds(result);
        }
    }

    /**
     * 添加查找到的节点到结果中，并排序
     * @param result
     * @param lookForNodes
     */
    protected void addFindNodesToResult(List<ITreeNode<DataTable, DataRow>> result, List<? extends ITreeNode<DataTable, DataRow>> lookForNodes)
    {
        // 如果不是层级，则直接插入
        if (tableConfig.getLevelColumnConfig() == null || CoreUtil.isEmpty(tableConfig.getLevelColumnConfig().getColumnName()))
        {
            // 不需要重新排序
            result.addAll(lookForNodes);
            return;
        }
        
        // 从result中查找不是本次插入的并且没有匹配上的节点的
        // 需要重新拍戏的节点
        List<CompareTreeNode> sorts = new ArrayList<CompareTreeNode>();
        for (int i = result.size() - 1; i > -1; i--)
        {
            CompareTreeNode treeNode = (CompareTreeNode) result.get(i);
            if (treeNode.isThisInsertNode() || treeNode.isThisHasMatch())
            {
                break;
            }
            sorts.add(treeNode);
        }
        if (CoreUtil.isEmpty(sorts))
        {
            // 不需要重新排序
            result.addAll(lookForNodes);
            return;
        }
        // 暂时只对 一, (一),（一）,1,1.1,1.1.1 这种格式的数据排序
        String value = CoreUtil.parseStr(sorts.get(0).getSource().getValue(tableConfig.getLevelColumnConfig().getColumnName()));
        if (CoreUtil.isEmpty(value))
        {
            // 不需要重新排序
            result.addAll(lookForNodes);
            return;
        }
        // 获取lookForNodes的第一校验需不需要排序
        String lookValue = CoreUtil.parseStr(lookForNodes.get(0).getSource().getValue(tableConfig.getLevelColumnConfig().getColumnName()));
        if (CoreUtil.isEmpty(lookValue))
        {
            // 不需要重新排序
            result.addAll(lookForNodes);
            return;
        }
        // 暂时只对 一, (一),（一）,1,1.1,1.1.1 这种格式的数据排序
        if ((ReGularUtil.CHINESENUMBER.matcher(value).matches() && ReGularUtil.CHINESENUMBER.matcher(lookValue).matches())
                || (ReGularUtil.CHINESENUMBERANDKH.matcher(value).matches() && ReGularUtil.CHINESENUMBERANDKH.matcher(lookValue).matches())
                || (ReGularUtil.LEVEL_PATTERN.matcher(value).matches() && ReGularUtil.LEVEL_PATTERN.matcher(lookValue).matches()))
        {
            // 先从 result中移除sorts
            for (int i = 0; i < sorts.size(); i++)
            {
                result.remove(result.size() - 1);
            }
            // 把 sorts和lookForNodes 合并并重新排序
            for (ITreeNode<DataTable, DataRow> treeNode : lookForNodes)
            {
                sorts.add((CompareTreeNode)treeNode);
            }
            Collections.sort(sorts, CompareTreeNode.getCompareTreeNodeComparator(tableConfig));
            result.addAll(sorts);
        } else
        {
            // 不需要重新排序
            result.addAll(lookForNodes);
        }
    }

    /**
     * 回溯匹配没有匹配上的节点
     * @param result
     * @param allNoMatchNodes
     */
    protected void reCallMatchTreeNodes(List<ITreeNode<DataTable, DataRow>> result, List<ITreeNode<DataTable, DataRow>> allNoMatchNodes)
    {
        CompareTreeNode treeNode = null;
        List<CompareTreeNode> lookForNodes = null;
        // 使用HashSet装入，提高查找效率
        Set<ITreeNode<DataTable, DataRow>> matchSet = new HashSet<ITreeNode<DataTable, DataRow>>();
        for (ITreeNode<DataTable, DataRow> iTreeNode : result)
        {
            if (!(iTreeNode instanceof CompareTreeNode))
            {
                continue;
            }
            treeNode = (CompareTreeNode) iTreeNode;
            // 插入的直接过滤
            if (treeNode.isThisInsertNode())
            {
                continue;
            }
            // 已经匹配上了
            if (treeNode.isThisHasMatch())
            {
                continue;
            }
            lookForNodes = lookForTreeNodesByCofing(treeNode, allNoMatchNodes);
            if (lookForNodes == null || lookForNodes.isEmpty())
            {
                continue;
            }
            // 移除匹配上的那一个
            ITreeNode<DataTable, DataRow> matchNode = allNoMatchNodes.remove(lookForNodes.size() - 1);
            matchSet.add(matchNode);
            // 如果匹配上了需要递归匹配子集
            if (!iTreeNode.getChildren().isEmpty() && !matchNode.getChildren().isEmpty())
            {
                combineTreeNode(treeNode, treeNode.getChildren(), matchNode.getRoot(), matchNode.getChildren());
            }
        }
        // 再次排查插入的节点中是否有nodeSet种节点，如果有则移除
        if (!matchSet.isEmpty() && tableConfig.isInsertNoMatch())
        {
            for (Iterator<ITreeNode<DataTable, DataRow>> iterator = result.iterator(); iterator.hasNext();)
            {
                ITreeNode<DataTable, DataRow> iTreeNode = (ITreeNode<DataTable, DataRow>) iterator.next();
                if (!(iTreeNode instanceof CompareTreeNode))
                {
                    continue;
                }
                treeNode = (CompareTreeNode) iTreeNode;
                if (!treeNode.isThisInsertNode())
                {
                    continue;
                }
                if (matchSet.contains(treeNode))
                {
                    iterator.remove();
                }
            }
        }
    }

    /**
     * 去target中查找和temp相等的节点
     * @param temp
     * @param target
     * @return 查找到的节点（temp节点）以及其兄长节点
     */
    protected List<CompareTreeNode> lookForTreeNodesByCofing(CompareTreeNode temp, List<ITreeNode<DataTable, DataRow>> target)
    {
        DataRow tempRow = temp.getSource();
        List<CompareTreeNode> result = new ArrayList<CompareTreeNode>();

        CompareTreeNode treeNode = null;
        for (ITreeNode<DataTable, DataRow> iTreeNode : target)
        {
            if (!(iTreeNode instanceof CompareTreeNode))
            {
                continue;
            }
            treeNode = (CompareTreeNode) iTreeNode;
            if (checkEquals(temp, treeNode))
            {
                // cb 2017 06 07 新增覆盖的功能
                if (tableConfig.getCoverColumnConfigs() != null)
                {
                    DataColumn column = null;
                    for (CoverColumnConfig columnConfig : tableConfig.getCoverColumnConfigs())
                    {
                        if (CoreUtil.isEmpty(columnConfig.getFirstColumnName()) || CoreUtil.isEmpty(columnConfig.getLastColumnName()))
                        {
                            continue;
                        }
                        // 覆盖值:有对应列才考虑覆盖
                        column = iTreeNode.getSource().getDataTable().getColumn(columnConfig.getLastColumnName());
                        if (column != null)
                        {
                            tempRow.getItemMap().put(columnConfig.getFirstColumnName(), iTreeNode.getSource().getItemMap().get(column.getColumnName()));
                        }
                    }
                }
                // 把之前的都设置为这次插入的节点和插入的节点
                for (CompareTreeNode resultNode : result)
                {
                    resultNode.setThisInsertNode(true);
                    resultNode.setInsertNode(true, true);
                }
                result.add(temp);
                temp.getMatchNodes().put(treeNode.getRoot().getSource(), treeNode);
                temp.setThisHasMatch(true);
                // 只有匹配上了才会考虑返回，所以最后一个一定是匹配上的节点
                // 如果是两棵树的对比，则设置matchNode
                if (isTwoDataTableCompare())
                {
                    temp.setMatchNode(treeNode);
                }
                return result;
            }
            else
            {
                result.add(treeNode);
            }
        }
        return null;
    }

    /**
     * 去target中查找和temp相等的节点并移除
     * @param temp
     * @param target
     * @return
     */
    protected CompareTreeNode lookForTreeNodeAndRemove(CompareTreeNode temp, List<ITreeNode<DataTable, DataRow>> target)
    {
        CompareTreeNode treeNode = null;
        for (Iterator<ITreeNode<DataTable, DataRow>> iterator = target.iterator(); iterator.hasNext();)
        {
            ITreeNode<DataTable, DataRow> iTreeNode = iterator.next();
            if (!(iTreeNode instanceof CompareTreeNode))
            {
                continue;
            }
            treeNode = (CompareTreeNode) iTreeNode;
            if (checkEquals(temp, treeNode))
            {
                iterator.remove();
                return treeNode;
            }
        }
        return null;
    }

    /**
     * 检查是都相等
     * @param temp
     * @param combine
     * @return
     */
    protected boolean checkEquals(CompareTreeNode temp, CompareTreeNode combine)
    {
        DataRow tempRow = temp.getSource();
        DataRow combineRow = combine.getSource();
        DataColumn tempEColumn = getDataColumnByColumnConfig(temp.getRoot().getSource(), tableConfig.getEqualsColumnConfig());
        DataColumn combineEColumn = getDataColumnByColumnConfig(combine.getRoot().getSource(), tableConfig.getEqualsColumnConfig());
                
        
        
        Set<String> otherEquals = tableConfig.getEqualsColumnConfig().getOtherColumnNames();
        Set<String> additiveCols = tableConfig.getEqualsColumnConfig().getAdditiveColumnNames();
        int equalsColimilarity = tableConfig.getEqualsColumnConfig().getSimilarity();
        int otherColSimilarity = tableConfig.getEqualsColumnConfig().getOtherColSimilarity();
        int additiveColSimilarity = tableConfig.getEqualsColumnConfig().getAdditiveColSimilarity();

        // 首先判断 equalsCol ，在判断 otherEquals 最后判断equalsCol的相似度
        String tempValue = tempEColumn == null ? null : CoreUtil.parseStr(tempRow.getItemMap().get(tempEColumn.getColumnName()));
        String combineValue = combineEColumn == null ? null : CoreUtil.parseStr(combineRow.getItemMap().get(combineEColumn.getColumnName()));
        
        Map<String, Set<String>> handSetEquals = tableConfig.getHandSetEquals();
        boolean result = checkEqualsImpl(tempValue, combineValue, handSetEquals, equalsColimilarity);
        // 2017 07 06 新增附加列判断
        boolean fjResult = true;
        if (!CoreUtil.isEmpty(additiveCols))
        {
            fjResult = false;
            for (String singleCol : additiveCols)
            {
                tempValue = CoreUtil.parseStr(tempRow.getItemMap().get(singleCol));
                combineValue = CoreUtil.parseStr(combineRow.getItemMap().get(singleCol));
                fjResult = checkEqualsImpl(tempValue, combineValue, handSetEquals, additiveColSimilarity);
                if (!fjResult)
                {
                    break;
                }
                // 附加列必须都要成立
                // if (fjResult)
                // {
                // break;
                // }
            }
        }
        result = result && fjResult;

        if (result || CoreUtil.isEmpty(otherEquals))
        {
            return result;
        }

        fjResult = true;
        if (CoreUtil.isEmpty(otherEquals))
        {
            return result;
        }
        else
        {
            sign: for (String singleCol : otherEquals)
            {
                tempValue = CoreUtil.parseStr(tempRow.getItemMap().get(singleCol));
                combineValue = CoreUtil.parseStr(combineRow.getItemMap().get(singleCol));
                result = checkEqualsImpl(tempValue, combineValue, handSetEquals, otherColSimilarity);
                if (result)
                {
                    // 2017 07 06 新增附加列判断
                    if (!CoreUtil.isEmpty(additiveCols))
                    {
                        fjResult = false;
                        for (String fjCol : additiveCols)
                        {
                            tempValue = CoreUtil.parseStr(tempRow.getItemMap().get(fjCol));
                            combineValue = CoreUtil.parseStr(combineRow.getItemMap().get(fjCol));
                            fjResult = checkEqualsImpl(tempValue, combineValue, handSetEquals, additiveColSimilarity);
                            // 附加列必须都成立
                            if (!fjResult)
                            {
                                continue sign;
                            }
                            // if (fjResult)
                            // {
                            // return result;
                            // }
                        }
                        return result;
                    }
                    else
                    {
                        return result;
                    }
                }
                else
                {
                    continue;
                }
            }
        }
        return result;
    }

    protected boolean checkEqualsImpl(String tempValue, String combineValue, Map<String, Set<String>> handSetEquals, int similarity)
    {
        // 将相等的条件改为忽略大小写，忽略中英文，忽略所有空格。
        if (CoreUtil.checkEqualIgnoreAllInfo(tempValue, combineValue, false))
        {
            return true;
        }
        if (similarity < 100)
        {
            if (Double.compare(SimilarityUtil.calcSimilarity(tempValue, combineValue) * 100, similarity) >= 0)
            {
                return true;
            }
        }
        // 新增手动设置相等的功能
        if (!CoreUtil.isEmpty(handSetEquals))
        {
            for (Entry<String, Set<String>> entry : handSetEquals.entrySet())
            {
                Set<String> sts = entry.getValue();
                if (CoreUtil.isEmpty(entry.getKey()) || CoreUtil.isEmpty(sts))
                {
                    continue;
                }
                if (CoreUtil.checkEqualIgnoreAllInfo(entry.getKey(), tempValue, false))
                {
                    for (String string : sts)
                    {
                        if (CoreUtil.checkEqualIgnoreAllInfo(combineValue, string, false))
                        {
                            return true;
                        }
                    }
                } else if (CoreUtil.checkEqualIgnoreAllInfo(entry.getKey(), combineValue, false))
                {
                    for (String string : sts)
                    {
                        if (CoreUtil.checkEqualIgnoreAllInfo(tempValue, string, false))
                        {
                            return true;
                        }
                    }
                } else 
                {
                    boolean tempMatch = CoreUtil.checkEqualIgnoreAllInfo(tempValue, entry.getKey(), false);
                    boolean combineMatch = CoreUtil.checkEqualIgnoreAllInfo(combineValue, entry.getKey(), false);
                    if (!tempMatch && !combineMatch)
                    {
                        continue;
                    }
                    for (String string : sts)
                    {
                        if (CoreUtil.checkEqualIgnoreAllInfo(tempValue, string, false) && combineMatch)
                        {
                            return true;
                        } else if (CoreUtil.checkEqualIgnoreAllInfo(combineValue, string, false) && tempMatch)
                        {
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }

    /**
     * 转成DataTable
     * @return
     * @throws Exception
     */
    @Override
    public DataTable toDataTable() throws Exception
    {
        // 转成DataTable
        DataTable result = new DataTable(tableConfig.getTableName());
        // 左右页眉
        if (!CoreUtil.isEmpty(tableConfig.getLeft()) || !CoreUtil.isEmpty(tableConfig.getRight()) || !CoreUtil.isEmpty(tableConfig.getTitle()))
        {
            result.setTitle(tableConfig.getTitle());
            result.setLeftHeader(tableConfig.getLeft());
            result.setRightHeader(tableConfig.getRight());
        }
        // 创建列
        Map<String, Integer> format = buildColumns(result);
        if (result.getColumns().isEmpty())
        {
            return result;
        }
        // 创建行
        buildRows(result);
        // 格式化
        formatResult(result, format);
        return result;
    }

    /**
     * 格式化结果
     * @param result
     * @param format
     */
    protected void formatResult(DataTable result, Map<String, Integer> format)
    {
        CoreUtil.formatDataTable(result, format);
    }

    /**
     * 创建行
     * @param result
     */
    protected void buildRows(DataTable result)
    {
        if (this.getChilds() == null || this.getChilds().isEmpty())
        {
            return;
        }
        convertTreeNode2DataRow(this.getChilds(), result, new CountEntity(-1));
    }

    /**
     * 将数节点转成DataRow
     * @param childs
     * @param result
     * @param count 行号计数器
     */
    protected void convertTreeNode2DataRow(List<ITreeNode<DataTable, DataRow>> childs, DataTable result, CountEntity count)
    {
        DataRow newRow = null;
        CompareTreeNode treeNode = null;
        for (ITreeNode<DataTable, DataRow> iTreeNode : childs)
        {
            if (!(iTreeNode instanceof CompareTreeNode))
            {
                continue;
            }
            treeNode = (CompareTreeNode) iTreeNode;
            // 换成该方式： 20170522:下面步骤的设置值统一访问方式
            treeNode.getMatchNodes().put(treeNode.getRoot().getSource(), treeNode);

            newRow = result.newRow();
            // 对比行是否是插入行的标记
            if (treeNode.isInsertNode())
            {
                newRow.getItemMap().put(CompareDataTable.对比行是否是插入行的标记, true);
            } else
            {
                // 对比行是否存在未匹配上的标记
                newRow.getItemMap().put(CompareDataTable.对比行是否存在未匹配上的标记, !CoreUtil.isEmpty(combineTrees) && treeNode.getMatchNodes().size() != combineTrees.size() + 1);
            }
            result.getRows().add(newRow);
            count.add();
            fillDisplayColumns(newRow, treeNode);
            fillCombineColumns(newRow, treeNode);
            fillCompareColumns(newRow, treeNode);
            fillCheckColumns(newRow, treeNode);
            fillExtendColumns(newRow, treeNode);
            if (tableConfig.isHasDiffReason() && isTwoDataTableCompare())
            {
                fillDiffrentReason(newRow, treeNode, count);
            }
            // 递归循环子节点
            if (!treeNode.getChildren().isEmpty())
            {
                convertTreeNode2DataRow(treeNode.getChildren(), result, count);
            }
        }
    }

    protected void fillDiffrentReason(DataRow newRow, CompareTreeNode treeNode, CountEntity count)
    {
        newRow.getItemMap().put(tableConfig.getDiffColumnName(), treeNode.getDiffReason());
        // 设置差异原因样式
        newRow.getItemMap().put(tableConfig.getDiffColumnName() + Data2Html.TDCLASS, CompareDataTable.差异原因样式);
        // td上的数据
        Map<String, Object> dataMap = new HashMap<String, Object>();
        if (treeNode.isDiffReasonOperate())
        {
            newRow.getItemMap().put(CompareDataTable.操作, CompareDataTable.操作值);
            dataMap.put("data-rowindex", count.getCount());
            if (!CoreUtil.isEmpty(tableConfig.getDiffColumnKey()))
            {
                if (treeNode.isInsertNode())
                {
                    String value = CoreUtil.parseStr(treeNode.getSource().getItemMap().get(tableConfig.getDiffColumnKey()));
                    dataMap.put("data-rowidone", "");
                    dataMap.put("data-rowidtwo", value);
                } else
                {
                    if (treeNode.getMatchNode() == null)
                    {
                        String value = CoreUtil.parseStr(treeNode.getSource().getItemMap().get(tableConfig.getDiffColumnKey()));
                        dataMap.put("data-rowidone", value);
                        dataMap.put("data-rowidtwo", "");
                    } else
                    {
                        String valueOne = CoreUtil.parseStr(treeNode.getSource().getItemMap().get(tableConfig.getDiffColumnKey()));
                        String valueTwo = CoreUtil.parseStr(treeNode.getMatchNode().getSource().getItemMap().get(tableConfig.getDiffColumnKey()));
                        dataMap.put("data-rowidone", valueOne);
                        dataMap.put("data-rowidtwo", valueTwo);
                    }
                }
            }
            // 把equalsColumn中的判定相等列也放进去
            DataColumn equCol = getDataColumnByColumnConfig(treeNode.getRoot().getSource(), tableConfig.getEqualsColumnConfig());
            String value = equCol == null ? "" : CoreUtil.parseStr(treeNode.getSource().getItemMap().get(equCol.getColumnName()));
            // 设置为链接
            StringBuilder jsFunParam = new StringBuilder(CompareDataTable.JSFUNC_OPENDIFFREASON).append("(this)");
            dataMap.put("data-equalsvalue", value);
            newRow.getItemMap().put(CompareDataTable.操作 + DataTable2Html.TDCLICK, jsFunParam.toString());
            newRow.getItemMap().put(CompareDataTable.操作 + DataTable2Html.TDDATAMAP, dataMap);
        }
    }

    protected void fillCheckColumns(DataRow newRow, CompareTreeNode treeNode)
    {
        // 对比显示列
        if (CoreUtil.isEmpty(tableConfig.getCheckColumnConfigs()) || CoreUtil.isEmpty(treeNode.getMatchNodes()))
        {
            return;
        }
        ColumnLoopTypeEnum columnLoopType = tableConfig.getColumnLoopType();
        boolean isColumnLoop = columnLoopType == null || ColumnLoopTypeEnum.按列循环 == columnLoopType;
        for (CheckColumnConfig columnConfig : tableConfig.getCheckColumnConfigs())
        {
            double hj = 0.0;
            for (Entry<DataTable, CompareTreeNode> entry : treeNode.getMatchNodes().entrySet())
            {
                CompareTreeNode otherNode = entry.getValue();
                DataTable table = entry.getKey();
                DataColumn column = getDataColumnByColumnConfig(table, columnConfig);
                if (column == null)
                {
                    continue;
                }
                String columnName = isColumnLoop ? columnConfig.getCreateColumnName() + ExcelHtmlUtil.REPLACEPOINTFLAG + table.getTableName() :
                    table.getTableName() + ExcelHtmlUtil.REPLACEPOINTFLAG + columnConfig.getCreateColumnName();
                newRow.getItemMap().put(columnName, otherNode.getSource().getItemMap().get(column.getColumnName()));
                hj = CoreUtil.add(hj, otherNode.getSource().getItemMap().get(column.getColumnName()));
            }
            // 对比显示列的合计列
            if (!CoreUtil.isEmpty(columnConfig.getTotalColName()))
            {
                String columnName = isColumnLoop ? columnConfig.getCreateColumnName() + ExcelHtmlUtil.REPLACEPOINTFLAG + columnConfig.getTotalColName() :
                    CompareDataTable.合计 + ExcelHtmlUtil.REPLACEPOINTFLAG + columnConfig.getCreateColumnName();
                newRow.getItemMap().put(columnName, hj);
            }
        }
    }

    protected void fillCompareColumns(DataRow newRow, CompareTreeNode treeNode)
    {
        // 比较列
        if (CoreUtil.isEmpty(tableConfig.getCompareColumnConfigs()))
        {
            return;
        }
        ColumnLoopTypeEnum columnLoopType = tableConfig.getColumnLoopType();
        boolean isColumnLoop = columnLoopType == null || ColumnLoopTypeEnum.按列循环 == columnLoopType;
        
        // 是否超过了设置的
        boolean passDiffPercent = false;
        for (CompareColumnConfig columnConfig : tableConfig.getCompareColumnConfigs())
        {
            Set<String> sets = new HashSet<String>();
            if (treeNode.getMatchNodes() != null && !treeNode.getMatchNodes().isEmpty())
            {
                for (Entry<DataTable, CompareTreeNode> entry : treeNode.getMatchNodes().entrySet())
                {
                    CompareTreeNode otherNode = entry.getValue();
                    DataTable table = entry.getKey();
                    DataColumn column = getDataColumnByColumnConfig(table, columnConfig);
                    if (column == null)
                    {
                        continue;
                    }
                    String columnName = isColumnLoop ? columnConfig.getCreateColumnName() + ExcelHtmlUtil.REPLACEPOINTFLAG + table.getTableName() : 
                                table.getTableName() + ExcelHtmlUtil.REPLACEPOINTFLAG + columnConfig.getCreateColumnName();
                    Object local = otherNode.getSource().getItemMap().get(column.getColumnName());
                    newRow.getItemMap().put(columnName, local);
                    sets.add(CoreUtil.parseStr(local));
                }
            }
            if (!CoreUtil.isEmpty(combineTrees))
            {
                // 个数不一致肯定认为是存在差异
                if (treeNode.getMatchNodes().size() != combineTrees.size() + 1)
                {
                    newRow.getItemMap().put(CompareDataTable.对比行是否存在对比列不一致的标记, true);
                } else
                {
                    newRow.getItemMap().put(CompareDataTable.对比行是否存在对比列不一致的标记, sets.size() > 1);
                }
            }
            
            // 差值,后者减前者
            String czColumnName = "";
            if (columnConfig.isCalDiff() && isTwoDataTableCompare())
            {
                // 此处应该不需要判定，因为所有信息都在MatchNodes()这个信息中
                CompareTreeNode matchNode = treeNode.getMatchNodes().get(combineTrees.get(0).getSource());
                DataColumn column = null;
                Object matchValue = null;
                if (matchNode != null)
                {
                    column = getDataColumnByColumnConfig(matchNode.getRoot().getSource(), columnConfig);
                    matchValue = column == null ? null : matchNode.getSource().getItemMap().get(column.getColumnName());
                }
                Object thisValue = null;
                CompareTreeNode thisNode = treeNode.getMatchNodes().get(this.getSource());
                if (thisNode != null)
                {
                    column = getDataColumnByColumnConfig(thisNode.getRoot().getSource(), columnConfig);
                    thisValue = column == null ? null : thisNode.getSource().getItemMap().get(column.getColumnName());
                }
                czColumnName = isColumnLoop ? columnConfig.getCreateColumnName() + ExcelHtmlUtil.REPLACEPOINTFLAG + CompareDataTable.差值 : 
                    CompareDataTable.差值 + ExcelHtmlUtil.REPLACEPOINTFLAG + columnConfig.getCreateColumnName();
                newRow.getItemMap().put(czColumnName, CoreUtil.subtract(matchValue, thisValue));
            }
            if (columnConfig.isCalDiffPercent() && isTwoDataTableCompare())
            {
                String columnName = isColumnLoop ? columnConfig.getCreateColumnName() + ExcelHtmlUtil.REPLACEPOINTFLAG + CompareDataTable.差率 : 
                    CompareDataTable.差率 + ExcelHtmlUtil.REPLACEPOINTFLAG + columnConfig.getCreateColumnName();
                CompareTreeNode thisNode = treeNode.getMatchNodes().get(this.getSource());
                // 这种情况则表示是插入的节点
                if (thisNode == null)
                {
                    // 此时差率是百分百
                    newRow.getItemMap().put(columnName, 100);
                }
                else
                {
                    // 差值/本身值
                    DataColumn column = getDataColumnByColumnConfig(treeNode.getRoot().getSource(), columnConfig);
                    newRow.getItemMap().put(columnName, 
                            CoreUtil.multiply(CoreUtil.divide(newRow.getItemMap().get(czColumnName), 
                                    treeNode.getSource().getItemMap().get(column == null ? columnConfig.getCreateColumnName() : column.getColumnName())), 100));
                }
                // 标红
                if (CoreUtil.compareNumberNoPrecision(Math.abs(CoreUtil.parseDbl(newRow.getItemMap().get(columnName))), tableConfig.getLabelLevel()) > -1)
                {
                    passDiffPercent = true;
                    newRow.getItemMap().put(DataTable2Html.TRSTYLE, "color:red;");
                }
            }
        }
        newRow.getItemMap().put(CompareDataTable.对比行是否存在差率超过设置的差率标记, passDiffPercent);
    }

    /**
     * 填充和并列
     * @param newRow
     * @param treeNode
     */
    protected void fillCombineColumns(DataRow newRow, CompareTreeNode treeNode)
    {
        // 和并列
        if (CoreUtil.isEmpty(tableConfig.getCombineColumnConfigs()) || CoreUtil.isEmpty(treeNode.getMatchNodes()))
        {
            return;
        }
        for (CombineColumnConfig columnConfig : tableConfig.getCombineColumnConfigs())
        {
            // 有合并
            for (Entry<DataTable, CompareTreeNode> entry : treeNode.getMatchNodes().entrySet())
            {
                DataColumn column = getDataColumnByColumnConfig(entry.getValue().getRoot().getSource(), columnConfig);
                if (column == null)
                {
                    continue;
                }
                newRow.getItemMap().put(columnConfig.getCreateColumnName(), 
                        CoreUtil.add(newRow.getItemMap().get(columnConfig.getCreateColumnName()), 
                                entry.getValue().getSource().getItemMap().get(column.getColumnName())));
            }
        }
    }
    
    /**
     * 填充扩展列
     * @param newRow
     * @param treeNode
     */
    protected void fillExtendColumns(DataRow newRow, CompareTreeNode treeNode)
    {
        // 扩展列
        if (CoreUtil.isEmpty(tableConfig.getExtendColumnConfigs()))
        {
            return;
        }
        for (ExtendColumnConfig columnConfig : tableConfig.getExtendColumnConfigs())
        {
            columnConfig.getColumnType().fillExtendColumn(columnConfig, newRow, treeNode, getCombineTrees().size());
        }
    }

    /**
     * 填充显示列
     * @param newRow
     * @param treeNode
     */
    protected void fillDisplayColumns(DataRow newRow, CompareTreeNode treeNode)
    {
        // 显示列
        if (CoreUtil.isEmpty(tableConfig.getDisplayColumns()))
        {
            return;
        }
        for (DisplayColumnConfig columnConfig : tableConfig.getDisplayColumns())
        {
            DataColumn column = getDataColumnByColumnConfig(treeNode.getRoot().getSource(), columnConfig);
            if (column == null)
            {
                continue;
            }
            newRow.getItemMap().put(columnConfig.getCreateColumnName(), treeNode.getSource().getItemMap().get(column.getColumnName()));
        }
    }

    /**
     * 创建列
     * @return 需要格式化的信息
     * @param result
     */
    protected Map<String, Integer> buildColumns(DataTable result)
    {
        // 如果是单列对比，只展示tableName
        boolean isSingleColCompare = false;
        // 如果是单列查看，只展示tableName
        boolean isSingleColCheck = false;
        // 是否是两种表对比
        boolean isTwoDataTableCompare = isTwoDataTableCompare();
        // 所有需要展示的列
        List<ColumnConfig> allDisplayColumnConfigs = new ArrayList<ColumnConfig>();
        if (!CoreUtil.isEmpty(tableConfig.getDisplayColumns()))
        {
            allDisplayColumnConfigs.addAll(tableConfig.getDisplayColumns());
        }
        if (!CoreUtil.isEmpty(tableConfig.getCombineColumnConfigs()))
        {
            allDisplayColumnConfigs.addAll(tableConfig.getCombineColumnConfigs());
        }
        if (!CoreUtil.isEmpty(tableConfig.getCompareColumnConfigs()))
        {
            isSingleColCompare = tableConfig.getCompareColumnConfigs().size() == 1;
            allDisplayColumnConfigs.addAll(tableConfig.getCompareColumnConfigs());
        }
        if (!CoreUtil.isEmpty(tableConfig.getCheckColumnConfigs()))
        {
            isSingleColCheck = tableConfig.getCheckColumnConfigs().size() == 1;
            allDisplayColumnConfigs.addAll(tableConfig.getCheckColumnConfigs());
        }
        if (!CoreUtil.isEmpty(tableConfig.getExtendColumnConfigs()))
        {
            allDisplayColumnConfigs.addAll(tableConfig.getExtendColumnConfigs());
        }
        boolean needSort = false;
        if (CoreUtil.isEmpty(allDisplayColumnConfigs))
        {
            return null;
        }
        for (ColumnConfig columnConfig : allDisplayColumnConfigs)
        {
            needSort = columnConfig.getShowOrder() > -1;
            if (needSort)
            {
                break;
            }
        }
        if (needSort)
        {
            Collections.sort(allDisplayColumnConfigs, new Comparator<ColumnConfig>()
            {
                @Override
                public int compare(ColumnConfig o1, ColumnConfig o2)
                {
                    return o1.getShowOrder() - o2.getShowOrder();
                }
            });
        }
        // 列循环方式
        ColumnLoopTypeEnum loopType = tableConfig.getColumnLoopType();
        Map<String, Integer> format = new HashMap<String, Integer>();
        if (loopType == null || ColumnLoopTypeEnum.按列循环 == loopType)
        {
            // 按列循环
            buildColumnLoopColumns(result, isSingleColCompare, isSingleColCheck, isTwoDataTableCompare,
                    allDisplayColumnConfigs, format);
        } else
        {
            // 按DataTable循环
            buildDataTableLoopColumns(result, isSingleColCompare, isSingleColCheck, isTwoDataTableCompare,
                    allDisplayColumnConfigs, format);
        }
        // 差异原因列和操作列
        if (tableConfig.isHasDiffReason() && isTwoDataTableCompare)
        {
            DataColumn newCol = new DataColumn(tableConfig.getDiffColumnName(), tableConfig.getDiffColumnLabel());
            newCol.setAlign(HeaderConfig.LEFT);
            newCol.setWidth(CompareDataTable.差异原因宽度);
            result.getColumns().add(newCol);
            newCol = new DataColumn(CompareDataTable.操作);
            newCol.setAlign(HeaderConfig.CENTER);
            newCol.setWidth(CompareDataTable.操作宽度);
            result.getColumns().add(newCol);
        }
        return format;
    }

    private void buildDataTableLoopColumns(DataTable result, boolean isSingleColCompare, boolean isSingleColCheck,
            boolean isTwoDataTableCompare, List<ColumnConfig> allDisplayColumnConfigs, Map<String, Integer> format)
    {
        List<CompareColumnConfig> compareColumnConfigs = new ArrayList<CompareColumnConfig>();
        List<CheckColumnConfig> checkColumnConfigs = new ArrayList<CheckColumnConfig>();
        
        for (ColumnConfig columnConfig : allDisplayColumnConfigs)
        {
            if (columnConfig instanceof CompareColumnConfig)
            {
                compareColumnConfigs.add((CompareColumnConfig)columnConfig);
            } else if (columnConfig instanceof CheckColumnConfig)
            {
                checkColumnConfigs.add((CheckColumnConfig)columnConfig);
            }
        }
        List<AbstractCompareTree> locals = new ArrayList<AbstractCompareTree>();
        locals.add(this);
        if (!CoreUtil.isEmpty(combineTrees))
        {
            locals.addAll(combineTrees);
        }
        
        DataColumn newCol = null;
        
        boolean createComapre = false;
        boolean createCheck = false;
        for (ColumnConfig temp : allDisplayColumnConfigs)
        {
            if (temp instanceof DisplayColumnConfig)
            {
                DisplayColumnConfig columnConfig = (DisplayColumnConfig) temp;
                newCol = new DataColumn(columnConfig.getCreateColumnName(), columnConfig.getColumnLabel());
                newCol.setAlign(columnConfig.getAlign());
                newCol.setWidth(columnConfig.getWidth());
                result.getColumns().add(newCol);
                if (columnConfig.getDecimal() > -1)
                {
                    format.put(columnConfig.getCreateColumnName(), columnConfig.getDecimal());
                }
            } else if (temp instanceof CombineColumnConfig)
            {
                CombineColumnConfig columnConfig = (CombineColumnConfig) temp;
                newCol = new DataColumn(columnConfig.getCreateColumnName(), columnConfig.getColumnLabel());
                newCol.setAlign(columnConfig.getAlign());
                newCol.setWidth(columnConfig.getWidth());
                result.getColumns().add(newCol);
                if (columnConfig.getDecimal() > -1)
                {
                    format.put(columnConfig.getCreateColumnName(), columnConfig.getDecimal());
                }
            } else if (temp instanceof CompareColumnConfig)
            {
                if (createComapre)
                {
                    continue;
                }
                createComapre = true;
                int treeIndex = -1;
                for (AbstractCompareTree tree : locals)
                {
                    treeIndex ++;
                    // 字母标识
                    String character = "";
                    if (isTwoDataTableCompare && CompareDataTable.对比列添加字母标记 && (compareColumnConfigs.get(0).isCalDiff() || compareColumnConfigs.get(0).isCalDiffPercent()))
                    {
                        character = treeIndex == 0 ? "（A）" : "（B）";
                    }
                    for (CompareColumnConfig columnConfig : compareColumnConfigs)
                    {
                        // 本树列
                        newCol = new DataColumn(tree.source.getTableName() + ExcelHtmlUtil.REPLACEPOINTFLAG + columnConfig.getCreateColumnName(), 
                                isSingleColCompare ? tree.source.getTableName() + character : tree.source.getTableName() + character + ExcelHtmlUtil.REPLACEPOINTFLAG + columnConfig.getColumnLabel());
                        newCol.setAlign(columnConfig.getAlign());
                        newCol.setWidth(columnConfig.getWidth());
                        result.getColumns().add(newCol);
                        if (columnConfig.getDecimal() > -1)
                        {
                            format.put(newCol.getColumnName(), columnConfig.getDecimal());
                        }
                    }
                }
                // 差值和差率
                if (isTwoDataTableCompare)
                {
                    // 字母标识
                    String character = CompareDataTable.对比列添加字母标记 ? "（B-A）" : "";
                    for (CompareColumnConfig columnConfig : compareColumnConfigs)
                    {
                        if (!columnConfig.isCalDiff())
                        {
                            continue;
                        }
                        newCol = new DataColumn(CompareDataTable.差值 + ExcelHtmlUtil.REPLACEPOINTFLAG + columnConfig.getCreateColumnName(), 
                                isSingleColCompare ? CompareDataTable.差值 + character : CompareDataTable.差值 + character + ExcelHtmlUtil.REPLACEPOINTFLAG + columnConfig.getColumnLabel());
                        newCol.setAlign(columnConfig.getAlign());
                        newCol.setWidth(columnConfig.getWidth());
                        result.getColumns().add(newCol);
                        if (columnConfig.getDecimal() > -1)
                        {
                            format.put(newCol.getColumnName(), columnConfig.getDecimal());
                        }
                    }
                }
                // 如果combineTrees的size为1并且设置了添加差值
                if (isTwoDataTableCompare)
                {
                    // 字母标识
                    String character = CompareDataTable.对比列添加字母标记 ? "（B-A）/A" : "";
                    for (CompareColumnConfig columnConfig : compareColumnConfigs)
                    {
                        if (!columnConfig.isCalDiffPercent())
                        {
                            continue;
                        }
                        newCol = new DataColumn(CompareDataTable.差率 + ExcelHtmlUtil.REPLACEPOINTFLAG + columnConfig.getCreateColumnName(), 
                                isSingleColCompare ? CompareDataTable.差率 + character : CompareDataTable.差率 + character + ExcelHtmlUtil.REPLACEPOINTFLAG + columnConfig.getColumnLabel());
                        newCol.setAlign(columnConfig.getAlign());
                        newCol.setWidth(columnConfig.getWidth());
                        result.getColumns().add(newCol);
                        if (columnConfig.getDecimal() > -1)
                        {
                            format.put(newCol.getColumnName(), columnConfig.getDecimal());
                        }
                    }
                }
            } else if (temp instanceof CheckColumnConfig)
            {
                if (createCheck)
                {
                    continue;
                }
                createCheck = true;
                for (CheckColumnConfig columnConfig : checkColumnConfigs)
                {
                    for (AbstractCompareTree tree : locals)
                    {
                        // 本树列
                        newCol = new DataColumn(tree.source.getTableName() + ExcelHtmlUtil.REPLACEPOINTFLAG + columnConfig.getCreateColumnName(), 
                                isSingleColCheck ? tree.source.getTableName() : tree.source.getTableName() + ExcelHtmlUtil.REPLACEPOINTFLAG + columnConfig.getColumnLabel());
                        newCol.setAlign(columnConfig.getAlign());
                        newCol.setWidth(columnConfig.getWidth());
                        result.getColumns().add(newCol);
                        if (columnConfig.getDecimal() > -1)
                        {
                            format.put(newCol.getColumnName(), columnConfig.getDecimal());
                        }
                    }
                }
                // 对比显示列的合计列
                for (CheckColumnConfig columnConfig : checkColumnConfigs)
                {
                    if (CoreUtil.isEmpty(columnConfig.getTotalColName()))
                    {
                        continue;
                    }
                    // 合计列
                    newCol = new DataColumn(CompareDataTable.合计 + ExcelHtmlUtil.REPLACEPOINTFLAG + columnConfig.getCreateColumnName(),
                            isSingleColCheck ? CompareDataTable.合计 : CompareDataTable.合计 + ExcelHtmlUtil.REPLACEPOINTFLAG + columnConfig.getColumnLabel());
                    newCol.setAlign(columnConfig.getAlign());
                    newCol.setWidth(columnConfig.getWidth());
                    result.getColumns().add(newCol);
                    // 字符串和日期不需要格式化
                    if (columnConfig.getDecimal() > -1)
                    {
                        format.put(newCol.getColumnName(), columnConfig.getDecimal());
                    }
                }
            } else if (temp instanceof ExtendColumnConfig)
            {
                ExtendColumnConfig columnConfig = (ExtendColumnConfig) temp;
                newCol = new DataColumn(columnConfig.getCreateColumnName(), columnConfig.getColumnLabel());
                newCol.setAlign(columnConfig.getAlign());
                newCol.setWidth(columnConfig.getWidth());
                result.getColumns().add(newCol);
                if (columnConfig.getDecimal() > -1)
                {
                    format.put(columnConfig.getCreateColumnName(), columnConfig.getDecimal());
                }
            }
        }
    }

    protected void buildColumnLoopColumns(DataTable result, boolean isSingleColCompare, boolean isSingleColCheck,
            boolean isTwoDataTableCompare, List<ColumnConfig> allDisplayColumnConfigs, Map<String, Integer> format)
    {
        DataColumn newCol = null;
        for (ColumnConfig temp : allDisplayColumnConfigs)
        {
            if (temp instanceof DisplayColumnConfig)
            {
                DisplayColumnConfig columnConfig = (DisplayColumnConfig) temp;
                newCol = new DataColumn(columnConfig.getCreateColumnName(), columnConfig.getColumnLabel());
                newCol.setAlign(columnConfig.getAlign());
                newCol.setWidth(columnConfig.getWidth());
                result.getColumns().add(newCol);
                if (columnConfig.getDecimal() > -1)
                {
                    format.put(columnConfig.getCreateColumnName(), columnConfig.getDecimal());
                }
            } else if (temp instanceof CombineColumnConfig)
            {
                CombineColumnConfig columnConfig = (CombineColumnConfig) temp;
                newCol = new DataColumn(columnConfig.getCreateColumnName(), columnConfig.getColumnLabel());
                newCol.setAlign(columnConfig.getAlign());
                newCol.setWidth(columnConfig.getWidth());
                result.getColumns().add(newCol);
                if (columnConfig.getDecimal() > -1)
                {
                    format.put(columnConfig.getCreateColumnName(), columnConfig.getDecimal());
                }
            } else if (temp instanceof CompareColumnConfig)
            {
                CompareColumnConfig columnConfig = (CompareColumnConfig) temp;
                // 本树列
                newCol = new DataColumn(columnConfig.getCreateColumnName() + ExcelHtmlUtil.REPLACEPOINTFLAG + source.getTableName(), 
                        isSingleColCompare ? source.getTableName() : columnConfig.getColumnLabel() + ExcelHtmlUtil.REPLACEPOINTFLAG + source.getTableName());
                if (isTwoDataTableCompare && CompareDataTable.对比列添加字母标记 && (columnConfig.isCalDiff() || columnConfig.isCalDiffPercent()))
                {
                    newCol.setColumnLable(newCol.getColumnLable() + "（A）");
                }
                newCol.setAlign(columnConfig.getAlign());
                newCol.setWidth(columnConfig.getWidth());
                result.getColumns().add(newCol);
                if (columnConfig.getDecimal() > -1)
                {
                    format.put(newCol.getColumnName(), columnConfig.getDecimal());
                }
                if (combineTrees != null && !combineTrees.isEmpty())
                {
                    // 合并的树列
                    for (AbstractCompareTree compareTree : combineTrees)
                    {
                        newCol = new DataColumn(columnConfig.getCreateColumnName() + ExcelHtmlUtil.REPLACEPOINTFLAG + compareTree.source.getTableName(), 
                                isSingleColCompare ? compareTree.source.getTableName() : columnConfig.getColumnLabel() + ExcelHtmlUtil.REPLACEPOINTFLAG + compareTree.source.getTableName());
                        if (isTwoDataTableCompare && CompareDataTable.对比列添加字母标记 && (columnConfig.isCalDiff() || columnConfig.isCalDiffPercent()))
                        {
                            newCol.setColumnLable(newCol.getColumnLable() + "（B）");
                        }
                        newCol.setAlign(columnConfig.getAlign());
                        newCol.setWidth(columnConfig.getWidth());
                        result.getColumns().add(newCol);
                        if (columnConfig.getDecimal() > -1)
                        {
                            format.put(newCol.getColumnName(), columnConfig.getDecimal());
                        }
                    }
                }
                // 如果combineTrees的size为1并且设置了添加差值
                if (isTwoDataTableCompare && columnConfig.isCalDiff())
                {
                    newCol = new DataColumn(columnConfig.getCreateColumnName() + ExcelHtmlUtil.REPLACEPOINTFLAG + CompareDataTable.差值, 
                            isSingleColCompare ? CompareDataTable.差值 : columnConfig.getColumnLabel() + ExcelHtmlUtil.REPLACEPOINTFLAG + CompareDataTable.差值);
                    if (CompareDataTable.对比列添加字母标记)
                    {
                        newCol.setColumnLable(newCol.getColumnLable() + "（B-A）");
                    }
                    newCol.setAlign(columnConfig.getAlign());
                    newCol.setWidth(columnConfig.getWidth());
                    result.getColumns().add(newCol);
                    if (columnConfig.getDecimal() > -1)
                    {
                        format.put(newCol.getColumnName(), columnConfig.getDecimal());
                    }
                }
                // 如果combineTrees的size为1并且设置了添加差值
                if (isTwoDataTableCompare && columnConfig.isCalDiffPercent())
                {
                    newCol = new DataColumn(columnConfig.getCreateColumnName() + ExcelHtmlUtil.REPLACEPOINTFLAG + CompareDataTable.差率, 
                            isSingleColCompare ? CompareDataTable.差率 : columnConfig.getColumnLabel() + ExcelHtmlUtil.REPLACEPOINTFLAG + CompareDataTable.差率);
                    if (CompareDataTable.对比列添加字母标记)
                    {
                        newCol.setColumnLable(newCol.getColumnLable() + "（B-A）/A");
                    }
                    newCol.setAlign(columnConfig.getAlign());
                    newCol.setWidth(columnConfig.getWidth());
                    result.getColumns().add(newCol);
                    if (columnConfig.getDecimal() > -1)
                    {
                        format.put(newCol.getColumnName(), columnConfig.getDecimal());
                    }
                }
            } else if (temp instanceof CheckColumnConfig)
            {
                CheckColumnConfig columnConfig = (CheckColumnConfig) temp;
                // 本树列
                newCol = new DataColumn(columnConfig.getCreateColumnName() + ExcelHtmlUtil.REPLACEPOINTFLAG + source.getTableName(), 
                        isSingleColCheck ? source.getTableName() : columnConfig.getColumnLabel() + ExcelHtmlUtil.REPLACEPOINTFLAG + source.getTableName());
                newCol.setAlign(columnConfig.getAlign());
                newCol.setWidth(columnConfig.getWidth());
                result.getColumns().add(newCol);
                if (columnConfig.getDecimal() > -1)
                {
                    format.put(newCol.getColumnName(), columnConfig.getDecimal());
                }
                if (combineTrees != null && !combineTrees.isEmpty())
                {
                    for (AbstractCompareTree compareTree : combineTrees)
                    {
                        // 其他树列
                        newCol = new DataColumn(columnConfig.getCreateColumnName() + ExcelHtmlUtil.REPLACEPOINTFLAG + compareTree.source.getTableName(), 
                                isSingleColCheck ? compareTree.source.getTableName() : columnConfig.getColumnLabel() + ExcelHtmlUtil.REPLACEPOINTFLAG + compareTree.source.getTableName());
                        newCol.setAlign(columnConfig.getAlign());
                        newCol.setWidth(columnConfig.getWidth());
                        result.getColumns().add(newCol);
                        if (columnConfig.getDecimal() > -1)
                        {
                            format.put(newCol.getColumnName(), columnConfig.getDecimal());
                        }
                    }
                }
                // 对比显示列的合计列
                if (!CoreUtil.isEmpty(columnConfig.getTotalColName()))
                {
                    // 合计列
                    newCol = new DataColumn(columnConfig.getCreateColumnName() + ExcelHtmlUtil.REPLACEPOINTFLAG + columnConfig.getTotalColName(),
                            isSingleColCheck ? columnConfig.getTotalColName() : columnConfig.getColumnLabel() + ExcelHtmlUtil.REPLACEPOINTFLAG + columnConfig.getTotalColName());
                    newCol.setAlign(columnConfig.getAlign());
                    newCol.setWidth(columnConfig.getWidth());
                    result.getColumns().add(newCol);
                    // 字符串和日期不需要格式化
                    if (columnConfig.getDecimal() > -1)
                    {
                        format.put(newCol.getColumnName(), columnConfig.getDecimal());
                    }
                }
            } else if (temp instanceof ExtendColumnConfig)
            {
                ExtendColumnConfig columnConfig = (ExtendColumnConfig) temp;
                newCol = new DataColumn(columnConfig.getCreateColumnName(), columnConfig.getColumnLabel());
                newCol.setAlign(columnConfig.getAlign());
                newCol.setWidth(columnConfig.getWidth());
                result.getColumns().add(newCol);
                if (columnConfig.getDecimal() > -1)
                {
                    format.put(columnConfig.getCreateColumnName(), columnConfig.getDecimal());
                }
            } 
        }
    }
    
    /**
     * 重新汇总父节点数据
     * @param reCollectColumns 需要重新汇总的列 key
     */
    public void reCollectParentData(Set<String> columnNames)
    {
        if (this.getChilds().isEmpty() || columnNames == null || columnNames.isEmpty())
        {
            return;
        }
        reCollectParentDataImpl(this.getChilds(), columnNames);
    }

    private void reCollectParentDataImpl(List<ITreeNode<DataTable, DataRow>> childs, Set<String> columnNames)
    {
        for (ITreeNode<DataTable, DataRow> node : childs)
        {
            // 叶子节点不考虑
            if (node.isLeaf())
            {
                continue;
            }
            List<ITreeNode<DataTable, DataRow>> allLeafs = DeepChildrenUtil.getLeafs(node);
            if (allLeafs == null || allLeafs.isEmpty())
            {
                continue;
            }
            for (String columnName : columnNames)
            {
                // 把自己的需要先清空
                node.getSource().getItemMap().put(columnName, null);
                for (ITreeNode<DataTable, DataRow> iTreeNode : allLeafs)
                {
                    node.getSource().getItemMap().put(columnName, CoreUtil.add(node.getSource().getItemMap().get(columnName), iTreeNode.getSource().getItemMap().get(columnName)));
                }
            }
            // 递归汇总子节点
            if (!CoreUtil.isEmpty(node.getChildren()))
            {
                reCollectParentDataImpl(node.getChildren(), columnNames);
            }
        }
    }
    

    /**
     * 重新汇总父节点数据
     * @param reCollectColumns 需要重新汇总的列 key:列名 value 小数位
     */
    public void reCollectParentData(Map<String, Integer> reCollectColumns)
    {
        if (this.getChilds().isEmpty() || reCollectColumns == null || reCollectColumns.isEmpty())
        {
            return;
        }
        reCollectParentDataImpl(this.getChilds(), reCollectColumns);
    }

    private void reCollectParentDataImpl(List<ITreeNode<DataTable, DataRow>> childs, Map<String, Integer> reCollectColumns)
    {
        for (ITreeNode<DataTable, DataRow> node : childs)
        {
            // 叶子节点不考虑
            if (node.isLeaf())
            {
                continue;
            }
            List<ITreeNode<DataTable, DataRow>> allLeafs = DeepChildrenUtil.getLeafs(node);
            if (allLeafs == null || allLeafs.isEmpty())
            {
                continue;
            }
            for (Entry<String, Integer> entry : reCollectColumns.entrySet())
            {
                // 把自己的需要先清空
                node.getSource().getItemMap().put(entry.getKey(), null);
                for (ITreeNode<DataTable, DataRow> iTreeNode : allLeafs)
                {
                    node.getSource().getItemMap().put(entry.getKey(), CoreUtil.add(node.getSource().getItemMap().get(entry.getKey()), iTreeNode.getSource().getItemMap().get(entry.getKey())));
                }
                // 格式化
                node.getSource().getItemMap().put(entry.getKey(), CoreUtil.parseDblStr(node.getSource().getItemMap().get(entry.getKey()), entry.getValue()));
            }
            // 递归汇总子节点
            if (!CoreUtil.isEmpty(node.getChildren()))
            {
                reCollectParentDataImpl(node.getChildren(), reCollectColumns);
            }
        }
    }

    /**
     * 是否是两个DataTable对比合并
     * @return
     */
    protected boolean isTwoDataTableCompare()
    {
        return combineTrees != null && combineTrees.size() == 1;
    }
    
    /**
     * 获取列配置对应的列（兼容列配置）
     * @param table
     * @param columnConfig
     * @return
     */
    public static DataColumn getDataColumnByColumnConfig(DataTable table, ColumnConfig columnConfig)
    {
        DataColumn result = table.getColumn(columnConfig.getColumnName());
        if (result == null && !CoreUtil.isEmpty(columnConfig.getCompatibleColumnNames()))
        {
            // 获取兼容列
            for (String columnName : columnConfig.getCompatibleColumnNames())
            {
                result = table.getColumn(columnName);
                if (result != null)
                {
                    break;
                }
            }
        }
        return result;
    }

    public CompareDataTableConfig getTableConfig()
    {
        return tableConfig;
    }

    public void setTableConfig(CompareDataTableConfig tableConfig)
    {
        this.tableConfig = tableConfig;
    }

    public List<AbstractCompareTree> getCombineTrees()
    {
        if (combineTrees == null)
        {
            combineTrees = new ArrayList<AbstractCompareTree>();
        }
        return combineTrees;
    }
    

}
